package logic_pay

import (
	"APT/internal/consts"
	"APT/internal/dao"
	"APT/internal/library/Paypal"
	"APT/internal/library/airhousePublicApi"
	"APT/internal/library/contexts"
	"APT/internal/library/mlilifeWxPay"
	"APT/internal/library/paycloud"
	"APT/internal/library/stripePay"
	"APT/internal/model/entity"
	"APT/internal/model/input/input_app_member"
	"APT/internal/model/input/input_basics"
	"APT/internal/model/input/input_pay"
	"APT/internal/model/input/input_refund"
	"APT/internal/service"
	"APT/utility/rabbitmq"
	"APT/utility/uuid"
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-pay/gopay/paypal"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/gclient"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/glog"
	"github.com/gogf/gf/v2/os/gmlock"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/shopspring/decimal"
	"github.com/stripe/stripe-go/v79"
)

// SelectThirdPay 选择第三方支付方式
func (s *sPayService) SelectThirdPay(ctx context.Context, in *input_pay.SelectThirdPayInp) (out *input_pay.SelectThirdPayModel, err error) {
	var (
		PmsTransactionInfo *entity.PmsTransaction
		paycloudClient     *paycloud.Client
		CreateAppOrder     paycloud.CreateAppPayOrderResponse
		CreateWebOrder     paycloud.CreateWebPayOrderResponse
		//CreateWxMiniOrder  paycloud.CreateWxMiniPayOrderResponse
		mlilifeWxPayWxappPayResponse *mlilifeWxPay.WxappPayResponse
		//mlilifeWxPayWxappQueryResponse *mlilifeWxPay.WxappQueryResponse
		PaypalClient       *Paypal.Client
		StripeClient       *stripePay.Client
		PaypalCardRespBody *paypal.OrderDetail
		StripeCardRespBody *stripe.CheckoutSession
		PaypalRespBody     *paypal.CreateOrderRsp
		PayParams          string
		TransNo            string
		PayChannel         string
		MemberUser         = contexts.GetMemberUser(ctx)
		MemberAuth         *entity.PmsMemberAuth
	)

	out = new(input_pay.SelectThirdPayModel)
	mod := dao.PmsTransaction.Ctx(ctx)
	// TODO 支付
	if in.OrderSn[:1] == "C" {
		mod = mod.Where(dao.PmsTransaction.Columns().OrderSn, in.OrderSn)
		mod = mod.Where(dao.PmsTransaction.Columns().OrderType, "CAR")
	} else if in.OrderSn[:1] == "S" {
		mod = mod.Where(dao.PmsTransaction.Columns().OrderSn, in.OrderSn)
		mod = mod.Where(dao.PmsTransaction.Columns().OrderType, "SPA")
	} else if in.OrderSn[:1] == "F" {
		mod = mod.Where(dao.PmsTransaction.Columns().OrderSn, in.OrderSn)
		mod = mod.Where(dao.PmsTransaction.Columns().OrderType, "FOOD")
	} else if in.OrderSn[:1] == "H" {
		if in.OrderSn[:2] == "HC" {
			mod = mod.Where(dao.PmsTransaction.Columns().ChangeOrderSn, in.OrderSn)
			mod = mod.Where(dao.PmsTransaction.Columns().OrderType, "BOOKING_CHANGE")
		} else {
			mod = mod.Where(dao.PmsTransaction.Columns().OrderSn, in.OrderSn)
			mod = mod.Where(dao.PmsTransaction.Columns().OrderType, "BOOKING")
		}
	} else {
		err = gerror.New("支付类型错误")
		return
	}
	if err = mod.WhereNot(dao.PmsTransaction.Columns().PayChannel, "SYSTEM").
		Scan(&PmsTransactionInfo); err != nil {
		return
	}
	if g.IsEmpty(PmsTransactionInfo) {
		err = gerror.New("订单不存在")
		return
	}
	if PmsTransactionInfo.PayStatus != "WAIT" {
		err = gerror.New("订单超时无法支付")
		return
	}
	PmsTransactionInfo.TransactionSn = uuid.CreatePayCode("PT")
	DefaultAmount := PmsTransactionInfo.Amount
	if paycloudClient, err = paycloud.NewClient(ctx); err != nil {
		return
	}
	if in.PayChannel == "Paypal" {
		PayChannel = "PAYPAL"
		if PaypalClient, err = Paypal.GetClient(ctx); err != nil {
			return
		}
		if PaypalRespBody, err = PaypalClient.CreatOrder(ctx, contexts.GetLanguage(ctx), DefaultAmount); err != nil {
			return
		}
		PayParams = PaypalRespBody.Response.Links[1].Href
		TransNo = PaypalRespBody.Response.Id
		out.WebPayUrl = PayParams
		out.PaypalPayUrl = PayParams
	} else if in.PayChannel == "PaypalCard" {
		PayChannel = "PAYPAL"
		if PaypalClient, err = Paypal.GetClient(ctx); err != nil {
			return
		}
		if PaypalCardRespBody, err = PaypalClient.CreatCardOrder(ctx, &input_pay.PaypalCardPayParams{
			CardName:    in.CardName,
			CardNumber:  in.CardNumber,
			CardExp:     in.CardExp,
			CardCvv:     in.CardCvv,
			Address:     in.Address,
			PostalCode:  in.PostalCode,
			CountryCode: in.CountryCode,
			Amount:      DefaultAmount,
		}); err != nil {
			return
		}
		if _, err = dao.PmsTransaction.Ctx(ctx).Where(g.MapStrAny{
			dao.PmsTransaction.Columns().Id: PmsTransactionInfo.Id,
		}).Update(g.MapStrAny{
			dao.PmsTransaction.Columns().CaptureId:        PaypalCardRespBody.PurchaseUnits[0].Payments.Captures[0].Id,
			dao.PmsTransaction.Columns().PaymentRequestId: PaypalCardRespBody.PurchaseUnits[0].Payments.Captures[0].Id,
			dao.PmsTransaction.Columns().PayAmount:        PaypalCardRespBody.PurchaseUnits[0].Payments.Captures[0].SellerReceivableBreakdown.NetAmount.Value,
			dao.PmsTransaction.Columns().PayCharge:        PaypalCardRespBody.PurchaseUnits[0].Payments.Captures[0].SellerReceivableBreakdown.PaypalFee.Value,
		}); err != nil {
			return
		}
	} else if in.PayChannel == "StripeCard" {
		PayChannel = "STRIPE"
		if StripeClient, err = stripePay.GetClient(ctx); err != nil {
			return
		}
		if StripeCardRespBody, err = StripeClient.Pay(ctx, gvar.New(DefaultAmount).Int64(), "JPY"); err != nil {
			return
		}
		if _, err = dao.PmsTransaction.Ctx(ctx).Where(g.MapStrAny{
			dao.PmsTransaction.Columns().Id: PmsTransactionInfo.Id,
		}).Update(g.MapStrAny{
			dao.PmsTransaction.Columns().PaymentRequestId: StripeCardRespBody.ClientReferenceID,
			dao.PmsTransaction.Columns().PayAmount:        StripeCardRespBody.AmountSubtotal,
			dao.PmsTransaction.Columns().PayCharge:        StripeCardRespBody.TotalDetails.AmountTax,
		}); err != nil {
			return
		}
		PayParams = StripeCardRespBody.URL
		TransNo = StripeCardRespBody.ClientReferenceID
		out.StripePayUrl = PayParams
	} else {
		TransNo = PmsTransactionInfo.TransactionSn
		PayChannel = "PAYCLOUD"
		//if in.PayChannel == "CreditLinkPay" || in.PayChannel == "Alipay+" {
		if in.PayChannel == "CreditLinkPay" {
			in.PayChannel = "CreditLinkPay"
			paycloudClient.Endpoint = "https://open.n-age.co.jp/api/entry"
			paycloudClient.AppID = "wz715fc0d10ee9d156"
			paycloudClient.MerchantNo = "312100007235"
			paycloudClient.StoreNo = "4122000030"
			paycloudClient.SubAppid = ""
			paycloudClient.PrivateKey = "MIIEpAIBAAKCAQEAjD4k7gtcR5AlLv06LKXyeyJXXJ6mFmgeC9vOwA7LHPdTSdDRz/QF73qU3ntUrVsUVWpnMh98lkSUp7G01kahPrUFg2dtUYYOQEPClmfUaUivn9O3l9StKzFJd8VKLryYFs1rx2ZVKCKlwce+p1O7qRaOQqCpp8l2K2dCtoYzPfu3EV33+PiyeybO3fHhYDFihJtCDfoeEjHkQrlOQ4CF3+FtLFGbshV4g7iGyA9ZAK6fSZzucKEmPzmAjNz43rGlzCx7py0doU4+MgGINllU/ObbFgk/gd6wQ4abjYGYUaz5/XIM2h31wn2a6V/QebkpXrhW1BQs/nu2akpkNDuTyQIDAQABAoIBADMtinSEGMzUwX0AU/ZvKKnewlq+WoXawPw63pwfyedsKizJ04c72d6msSTvhNsuXaE+DyKvctuzczwvEXsQk0866CQn3jDd5t103NHeWhmBuPVuYZU6u2cDuXfHu2aK1EWd+TLvGSxoWGz644xUdisiXA/caY0da84zBJlvJ8v6Ps9ZzDHbe+2y3XR1cFVqhDMbssvA0SEXC1OsqkHa4qPsup7dH2IwOZSoYgIYHI3oZjRQKaXixmtG2clBp1LFxIR6X8r2xsFaoeJuuUcF4tWeXZgUrrKpdORi8qeqsGIz4sDURjHoZjCwiMmACge5Q4Vlb8JO4py68Rzp0eJyhsECgYEA5hp3dC9z4lVi97sLDXhF89MNyPAt0SeXoQ3NtaT7VCCDV62pB7Vk2PndeQMtbalQCKfiA4uY38ow9kaBOxI3IMpNthBe0s+0FTSRby1YuiC5W6Lf/rTTEK3jLO/H5GABV5rOhyqU+MzVsMXNKMpIzPFlAZRqwRpLLezWRzpPle0CgYEAnAaxeFDoeIhBhBRbG+SMqYGOcACZ8FOhMcBUu528w86z3Gy4nDcYipd+PelA/IgrjMa9uPLbh1hVK5s6CeEPyRq3NNrbSkLAXFDLjpc0eon1CAIk2ylbLmaVssCFVndMRY0qfYb1yKtBI56pWlGBy6LLCR+mSTbPECJk7RrB+c0CgYEA4ueid+37RmuRBl1pzsSVppSu+UDuzVtPiL/F5KNmO1U8b4+OKU3UvqnWnehmOcdGZuK2W2yjObt2gMSR1yBlQG5+J1UJTLUJDggiihGbdx+h6R056T+DCuWOKdfhs/CAIlVD58Iz2QyUhJbpcpnXJFG+msoyY218STNNMjvsExkCgYAO9oFchX3V2VNXJFCcey2WL+uGCDi7GHoT+Frn5zesG42aLP8DVDFRUTf1HgJydWifxot5SikNcMYyOV+2hNPruFkrg3WWSJKEB+eNlCifO8245+O69Ntets3SZ64h3az92ozhnujBRtMnZFbfZ4OoEMOh61waF1yCMpo1NuS1XQKBgQCPiBSz7paaWB9r1mc4t0QMpFLENuQECnsBHRn8sUy15Ij7NVo93k8plSuldvP4zzoIAX4SGsW9XYC7nEoc9Tc6Eo5Z9lzoIaeWXtyyTiF/zYrQNOMUDej1jwdFzgVvOAxiU/pHEb3R/jgiRN32nc7e1uguSb2SElKXi2t/++eMWg=="
			if CreateWebOrder, err = paycloudClient.WebOrder(ctx, &paycloud.CreateWebPayOrderParams{
				MerchantOrderNo: PmsTransactionInfo.TransactionSn,
				OrderAmount:     DefaultAmount,
			}); err != nil {
				return
			}
			out.AppPayParams = CreateWebOrder.Data.PayUrl
			PayParams = out.WebPayUrl
		} else if in.PayChannel == "Alipay+" {
			if CreateAppOrder, err = paycloudClient.AppOrder(ctx, &paycloud.CreateAppPayOrderParams{
				MerchantOrderNo: PmsTransactionInfo.TransactionSn,
				OrderAmount:     DefaultAmount,
				PayMethodID:     in.PayChannel,
			}); err != nil {
				return
			}
			out.AppPayParams = CreateAppOrder.Data.PayParams.PaymentUrl
			PayParams = out.AppPayParams
		} else if in.PayChannel == "WeChatPay" {
			if CreateAppOrder, err = paycloudClient.AppOrder(ctx, &paycloud.CreateAppPayOrderParams{
				MerchantOrderNo: PmsTransactionInfo.TransactionSn,
				OrderAmount:     DefaultAmount,
				PayMethodID:     in.PayChannel,
			}); err != nil {
				return
			}
			out.AppWechatPayParams.Appid = CreateAppOrder.Data.PayParams.Appid
			out.AppWechatPayParams.Package = CreateAppOrder.Data.PayParams.Package
			out.AppWechatPayParams.Partnerid = CreateAppOrder.Data.PayParams.Partnerid
			out.AppWechatPayParams.Prepayid = CreateAppOrder.Data.PayParams.Prepayid
			out.AppWechatPayParams.Noncestr = CreateAppOrder.Data.PayParams.Noncestr
			out.AppWechatPayParams.Timestamp = CreateAppOrder.Data.PayParams.Timestamp
			out.AppWechatPayParams.Sign = CreateAppOrder.Data.PayParams.Sign
			out.AppPayParams = gjson.New(CreateAppOrder.Data.PayParams).String()
			PayParams = out.AppPayParams
		} else if in.PayChannel == "WeChatMiniPay" {
			PayChannel = "MLILIFE"
			if err = dao.PmsMemberAuth.Ctx(ctx).Where(g.MapStrAny{
				dao.PmsMemberAuth.Columns().MemberId: MemberUser.Id,
				dao.PmsMemberAuth.Columns().Channel:  "WX_MINI",
			}).Scan(&MemberAuth); err != nil {
				return
			}
			if g.IsEmpty(MemberAuth) {
				err = gerror.New("请先绑定微信小程序")
				return
			}
			if g.IsEmpty(MemberAuth.AuthId) {
				err = gerror.New("请先绑定微信小程序")
				return
			}
			if mlilifeWxPayWxappPayResponse, err = mlilifeWxPay.WxappPay(ctx, &mlilifeWxPay.WxappPayRequest{
				Openid:     MemberAuth.AuthId,
				Body:       "房间预订",
				TotalFee:   gvar.New(DefaultAmount).Int(),
				OutTradeNo: PmsTransactionInfo.TransactionSn,
			}); err != nil {
				return
			}

			//if CreateWxMiniOrder, err = paycloudClient.WxMiniOrder(ctx, &paycloud.CreateWxMiniPayOrderParams{
			//	MerchantOrderNo: PmsTransactionInfo.TransactionSn,
			//	OrderAmount:     DefaultAmount,
			//	PayMethodID:     in.PayChannel,
			//	SubOpenid:       MemberAuth.AuthId,
			//}); err != nil {
			//	return
			//}
			out.WxMiniPayParams = gjson.New(mlilifeWxPayWxappPayResponse.Data).String()
			PayParams = out.WxMiniPayParams
			//if mlilifeWxPayWxappQueryResponse,err = mlilifeWxPay.WxappQuery(ctx, &mlilifeWxPay.WxappQueryParams{
			//	OutTradeNo: PmsTransactionInfo.TransactionSn,
			//});err != nil{
			//	return
			//}
			TransNo = ""
		}
	}

	// 更新三方支付信息
	if _, err = dao.PmsTransaction.Ctx(ctx).Where(g.MapStrAny{
		dao.PmsTransaction.Columns().Id: PmsTransactionInfo.Id,
	}).OmitEmptyData().Data(&entity.PmsTransaction{
		TransactionSn:    PmsTransactionInfo.TransactionSn,
		PayChannel:       PayChannel,
		PayType:          in.PayChannel,
		PayParams:        PayParams,
		PaymentRequestId: TransNo,
		ExpiredTime:      gtime.Now().Add(gtime.M * 10),
	}).Update(); err != nil {
		return
	}
	return
}

// BalancePay 纯余额支付
func (s *sPayService) BalancePay(ctx context.Context, in *input_pay.BalancePayInp) (out *input_pay.BalancePayModel, err error) {
	var (
		PmsAppStayInfo             *entity.PmsAppStay
		CarOrder                   *entity.CarOrder
		FoodOrder                  *entity.FoodOrder
		SpaOrder                   *entity.SpaOrder
		PmsTransactionBalAmount    float64
		PmsTransactionCouponAmount float64
		tx                         gdb.TX
		OrderAmount                float64
		MemberId                   int
		PayType                    string
	)
	// 纯余额支付
	g.Log().Info(ctx, "MemberBalancePay", in)
	g.Log().Info(ctx, "纯余额支付")
	// 开启事务
	if tx, err = g.DB().Begin(ctx); err != nil {
		return
	}
	defer func() {
		if err != nil {
			g.Log().Error(ctx, err)
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()
	if in.OrderSn[:1] == "H" {
		// 查询住宿订单
		if err = dao.PmsAppStay.Ctx(ctx).Where(dao.PmsAppStay.Columns().OrderSn, in.OrderSn).Scan(&PmsAppStayInfo); err != nil {
			return
		}
		if g.IsEmpty(PmsAppStayInfo) {
			err = gerror.New("订单错误,无法进行支付")
			return
		}
		if PmsAppStayInfo.PayModel != 1 {
			err = gerror.New("不是纯余额支付订单,无法进行支付")
			return
		}
		if PmsAppStayInfo.ExpirationTime < gvar.New(gtime.Now().Unix()).Int() {
			err = gerror.New("订单已过期,无法进行支付")
			return
		}
		OrderAmount = PmsAppStayInfo.OrderAmount
		MemberId = PmsAppStayInfo.MemberId
		PayType = "住宿"
	} else if in.OrderSn[:1] == "C" {
		// 查询出现订单
		if err = dao.CarOrder.Ctx(ctx).Where(dao.CarOrder.Columns().OrderSn, in.OrderSn).Scan(&CarOrder); err != nil {
			return
		}
		if g.IsEmpty(CarOrder) {
			err = gerror.New("订单错误,无法进行支付")
			return
		}
		if CarOrder.PayModel != 1 {
			err = gerror.New("不是纯余额支付订单,无法进行支付")
			return
		}
		if CarOrder.ExpirationTime < gvar.New(gtime.Now().Unix()).Int() {
			err = gerror.New("订单已过期,无法进行支付")
			return
		}
		OrderAmount = CarOrder.OrderAmount
		MemberId = gvar.New(CarOrder.MemberId).Int()
		PayType = "出行"
	} else if in.OrderSn[:1] == "F" {
		// 查询餐饮订单
		if err = dao.FoodOrder.Ctx(ctx).Where(dao.FoodOrder.Columns().OrderSn, in.OrderSn).Scan(&FoodOrder); err != nil {
			return
		}
		if g.IsEmpty(FoodOrder) {
			err = gerror.New("订单错误,无法进行支付")
			return
		}
		if FoodOrder.PayModel != 1 {
			err = gerror.New("不是纯余额支付订单,无法进行支付")
			return
		}
		if FoodOrder.ExpirationTime < gvar.New(gtime.Now().Unix()).Int() {
			err = gerror.New("订单已过期,无法进行支付")
			return
		}
		OrderAmount = FoodOrder.OrderAmount
		MemberId = gvar.New(FoodOrder.MemberId).Int()
		PayType = "餐饮"
	} else if in.OrderSn[:1] == "S" {
		// 查询 Spa 订单
		if err = dao.SpaOrder.Ctx(ctx).Where(dao.SpaOrder.Columns().OrderSn, in.OrderSn).Scan(&SpaOrder); err != nil {
			return
		}
		if g.IsEmpty(SpaOrder) {
			err = gerror.New("订单错误,无法进行支付")
			return
		}
		if SpaOrder.PayModel != 1 {
			err = gerror.New("不是纯余额支付订单,无法进行支付")
			return
		}
		if SpaOrder.ExpirationTime < gvar.New(gtime.Now().Unix()).Int() {
			err = gerror.New("订单已过期,无法进行支付")
			return
		}
		OrderAmount = SpaOrder.OrderAmount
		MemberId = gvar.New(SpaOrder.MemberId).Int()
		PayType = "按摩"
	} else {
		err = gerror.New("订单错误,无法进行支付")
		return
	}
	// 查询支付订单金额
	if PmsTransactionBalAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(g.MapStrAny{
		dao.PmsTransaction.Columns().OrderSn:   in.OrderSn,
		dao.PmsTransaction.Columns().PayType:   "BAL",
		dao.PmsTransaction.Columns().PayStatus: "WAIT",
	}).Sum(dao.PmsTransaction.Columns().Amount); err != nil {
		return
	}

	if PmsTransactionCouponAmount, err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(g.MapStrAny{
		dao.PmsTransaction.Columns().OrderSn:   in.OrderSn,
		dao.PmsTransaction.Columns().PayType:   "COUPON",
		dao.PmsTransaction.Columns().PayStatus: "DONE",
	}).Sum(dao.PmsTransaction.Columns().Amount); err != nil {
		return
	}

	if PmsTransactionBalAmount > 0 && (PmsTransactionBalAmount+PmsTransactionCouponAmount) != OrderAmount {
		err = gerror.New("支付金额错误")
		return
	}

	if err = service.PayService().OrderBalancePay(ctx, tx, in.OrderSn, MemberId, PayType); err != nil {
		return
	}

	if in.OrderSn[:1] == "H" {
		if _, err = s.HotelCreateOrder(ctx, &input_pay.HotelCreateOrderInp{
			OrderSn:                 in.OrderSn,
			PmsTransactionBalAmount: PmsTransactionBalAmount,
			Booker:                  PmsAppStayInfo.Booker,
		}, tx); err != nil {
			return
		}
	} else if in.OrderSn[:1] == "C" {
		// TODO -出行订单支付完成
		if err = service.PayService().HandleCarOrderMq(ctx, in.OrderSn, g.Log()); err != nil {
			g.Log().Error(ctx, err.Error())
		}
	} else if in.OrderSn[:1] == "S" {
		// TODO -按摩订单支付完成
		if err = service.PayService().HandleSpaOrderMq(ctx, in.OrderSn, g.Log()); err != nil {
			g.Log().Error(ctx, err.Error())
		}
	} else if in.OrderSn[:1] == "F" {
		// TODO -餐饮订单支付完成
		if err = service.PayService().HandleFoodOrderMq(ctx, in.OrderSn, g.Log()); err != nil {
			g.Log().Error(ctx, err.Error())
		}
	}
	return
}

func (s *sPayService) HotelCreateOrder(ctx context.Context, in *input_pay.HotelCreateOrderInp, tx gdb.TX) (out *input_pay.HotelCreateOrderModel, err error) {
	var (
		cookieBookerParams  *airhousePublicApi.CreateStayJSONDataRequest
		BookerResponse      *airhousePublicApi.CreateStayJSONDataResponse
		BookerResponseBytes []byte
	)
	// 修改住宿订单状态
	if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, in.OrderSn).Update(g.MapStrAny{
		dao.PmsAppStay.Columns().OrderStatus: "HAVE_PAID",
	}); err != nil {
		return
	}
	// 修改房间订单状态
	if _, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().OrderSn, in.OrderSn).Update(g.MapStrAny{
		dao.PmsAppReservation.Columns().OrderStatus: "HAVE_PAID",
	}); err != nil {
		return
	}
	// 修改支付订单状态
	if _, err = dao.PmsTransaction.Ctx(ctx).TX(tx).OmitEmptyData().
		Where(dao.PmsTransaction.Columns().ExpiredTime+" > ?", gtime.Now().Format("Y-m-d H:i:s")).
		Where(dao.PmsTransaction.Columns().OrderSn, in.OrderSn).
		Where(dao.PmsTransaction.Columns().PayType, "BAL").
		Update(entity.PmsTransaction{
			PayAmount: in.PmsTransactionBalAmount,
			PayStatus: "DONE",
			PayTime:   gtime.Now(),
		}); err != nil {
		return
	}
	// 获取 AIR_HOST 下单参数
	if cookieBookerParams, err = service.HotelService().CreateStayParams(ctx, in.OrderSn); err != nil {
		return
	}
	// 析构函数 提交事务
	defer func() {
		if err != nil {
			g.Log().Error(ctx, err)
			if err = service.HotelService().OrderExpiration(ctx, in.OrderSn); err != nil {
				err = gerror.New("订单内部支付失败情况下自动取消订单失败")
				return
			}
		} else {
			if BookerResponseBytes, err = json.Marshal(&BookerResponse.Data); err != nil {
				return
			}
			if err = rabbitmq.SendMqMessage(ctx, &rabbitmq.SendMqMessageParams{
				ExchangeName: consts.RabbitMQExchangeName,
				QueueName:    consts.RabbitMQQueueNameOrderStay,
				DataByte:     BookerResponseBytes,
				Header:       nil,
			}); err != nil {
				return
			}
		}
	}()
	// 提交订单
	if BookerResponse, err = service.HotelService().CreateStay(ctx, cookieBookerParams, tx); err != nil {
		return
	}
	// 修改住宿订单为支付完成
	if _, err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, in.OrderSn).Update(g.Map{
		dao.PmsAppStay.Columns().OrderStatus: "HAVE_PAID",
		dao.PmsAppStay.Columns().Uuid:        BookerResponse.Data.ID,
		dao.PmsAppStay.Columns().Booker:      BookerResponse.Data.Booker.ID,
	}); err != nil {
		return
	}
	// 修改入住人ID
	if _, err = dao.PmsGuestProfile.Ctx(ctx).TX(tx).Where(g.Map{
		dao.PmsGuestProfile.Columns().Uid: in.Booker,
	}).Data(g.Map{
		dao.PmsGuestProfile.Columns().Uid: BookerResponse.Data.Booker.ID,
	}).Update(); err != nil {
		return
	}

	// 修改房间订单为支付完成
	if _, err = dao.PmsAppReservation.Ctx(ctx).TX(tx).Where(dao.PmsAppReservation.Columns().OrderSn, in.OrderSn).Update(g.Map{
		dao.PmsAppReservation.Columns().OrderStatus: "HAVE_PAID",
		dao.PmsAppReservation.Columns().MainGuest:   BookerResponse.Data.Booker.ID,
	}); err != nil {
		return
	}

	// 酒店订单支付成功
	var (
		PmsAppStay entity.PmsAppStay
	)
	if err = dao.PmsAppStay.Ctx(ctx).Where(g.MapStrAny{
		dao.PmsAppStay.Columns().OrderSn: in.OrderSn,
	}).Scan(&PmsAppStay); err != nil && errors.Is(err, sql.ErrNoRows) {
		return
	}
	if g.IsEmpty(PmsAppStay) {
		err = gerror.New("该订单无需处理")
		return
	}
	if _, err = dao.PmsAppStayLog.Ctx(ctx).OmitEmptyData().Insert(&entity.PmsAppStayLog{
		OrderId:     PmsAppStay.Id,
		ActionWay:   "HAVE_PAID",
		Remark:      "订单支付",
		OperateType: "USER",
		OperateId:   PmsAppStay.MemberId,
	}); err != nil {
		return
	}
	return
}

// ThirdPayCompleted 三方支付完成后处理支付流水
func (s *sPayService) ThirdPayCompleted(ctx context.Context, in *input_pay.ThirdPayInp) (err error) {
	var (
		PmsTransaction          *entity.PmsTransaction
		PmsAppStay              *entity.PmsAppStay
		FoodOrder               *entity.FoodOrder
		SpaOrder                *entity.SpaOrder
		CarOrder                *entity.CarOrder
		PmsAppReservationChange *entity.PmsAppReservationChange
		tx                      gdb.TX
		lockKey                 = "nitifyOrder:" + in.TransNo
		OrderSn                 string
		OrderStatus             string
		MemberId                int
		PayType                 string
		OrderAmount             float64
	)
	defer func() {
		if err != nil {
			_ = service.WarningWorkWx().SendWarningWorkWx(ctx, `
### 三方支付完成后流水处理 ThirdPayCompleted
*  链路ID：`+gctx.CtxId(ctx)+`
* `+err.Error())
		}
	}()
	// 内存锁 防止重复执行该逻辑
	gmlock.Lock(lockKey)
	defer gmlock.Unlock(lockKey)
	// 开启事务处理
	if tx, err = g.DB().Begin(ctx); err != nil {
		return
	}
	// 析构函数 提交事务
	defer func() {
		if err != nil {
			g.Log().Error(ctx, err)
			_ = tx.Rollback()
		} else {
			g.Log().Infof(ctx, "支付前订单状态：%s", OrderStatus)
			if OrderStatus == "CANCEL" || OrderStatus == "FAIL" {
				err = service.Refund().RefundOrder(ctx, &input_refund.RefundAmountInp{
					OrderSn:      OrderSn,
					RefundAmount: OrderAmount,
				}, tx)
				_ = tx.Commit()
			} else {
				_ = tx.Commit()
				mqstruct := &rabbitmq.SendMqMessageParams{
					ExchangeName: consts.RabbitMQExchangeName,
					QueueName:    consts.RabbitMQQueueNamePlaceOrder,
					DataByte:     []byte(OrderSn),
					Header:       nil,
				}
				g.Log().Info(ctx, mqstruct)
				if err = rabbitmq.SendMqMessage(ctx, mqstruct); err != nil {
					return
				}
			}

		}
	}()

	// 查询支付信息
	if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().PaymentRequestId, in.TransNo).Scan(&PmsTransaction); err != nil {
		err = gerror.New("查询支付信息失败")
		return
	}
	// TODO 支付回调
	if PmsTransaction.OrderType == "CAR" {
		// 查询出行订单
		if err = dao.CarOrder.Ctx(ctx).TX(tx).Where(dao.CarOrder.Columns().OrderSn, PmsTransaction.OrderSn).Scan(&CarOrder); err != nil {
			return
		}
		OrderStatus = CarOrder.OrderStatus
		OrderSn = CarOrder.OrderSn
		MemberId = gvar.New(CarOrder.MemberId).Int()
		PayType = "出行"
		OrderAmount = CarOrder.OrderAmount
	} else if PmsTransaction.OrderType == "SPA" {
		// 查询按摩订单
		if err = dao.SpaOrder.Ctx(ctx).TX(tx).Where(dao.SpaOrder.Columns().OrderSn, PmsTransaction.OrderSn).Scan(&SpaOrder); err != nil {
			return
		}
		OrderStatus = SpaOrder.OrderStatus
		OrderSn = SpaOrder.OrderSn
		MemberId = gvar.New(SpaOrder.MemberId).Int()
		PayType = "按摩"
		OrderAmount = SpaOrder.OrderAmount
	} else if PmsTransaction.OrderType == "FOOD" {
		// 查询餐饮订单
		if err = dao.FoodOrder.Ctx(ctx).TX(tx).Where(dao.FoodOrder.Columns().OrderSn, PmsTransaction.OrderSn).Scan(&FoodOrder); err != nil {
			return
		}
		OrderStatus = FoodOrder.OrderStatus
		OrderSn = FoodOrder.OrderSn
		MemberId = gvar.New(FoodOrder.MemberId).Int()
		PayType = "餐饮"
		OrderAmount = FoodOrder.OrderAmount
	} else if PmsTransaction.OrderType == "BOOKING" {
		// 查询住宿单信息
		if err = dao.PmsAppStay.Ctx(ctx).TX(tx).Where(dao.PmsAppStay.Columns().OrderSn, PmsTransaction.OrderSn).Scan(&PmsAppStay); err != nil {
			err = gerror.New("查询住宿单信息失败")
			return
		}
		OrderStatus = PmsAppStay.OrderStatus
		OrderSn = PmsAppStay.OrderSn
		MemberId = gvar.New(PmsAppStay.MemberId).Int()
		PayType = "住宿"
		OrderAmount = PmsAppStay.OrderAmount
	} else if PmsTransaction.OrderType == "BOOKING_CHANGE" {
		// 查询住宿变更单
		if err = dao.PmsAppReservationChange.Ctx(ctx).TX(tx).
			Where(dao.PmsAppReservationChange.Columns().ChangeOrderSn, PmsTransaction.ChangeOrderSn).
			Scan(&PmsAppReservationChange); err != nil {
			err = gerror.New("查询住宿单信息失败")
			return
		}
		OrderStatus = PmsAppReservationChange.ChangeStatus
		OrderSn = PmsAppReservationChange.ChangeOrderSn
		OrderAmount = PmsAppReservationChange.ChangeAmount
	} else {
		err = gerror.New("订单类型错误")
		return
	}

	updateData := g.Map{
		dao.PmsTransaction.Columns().PayStatus: "DONE",
		dao.PmsTransaction.Columns().PayTime:   gtime.Now(),
	}
	if PmsTransaction.PayType != "Paypal" {
		updateData[dao.PmsTransaction.Columns().PayAmount] = PmsTransaction.Amount
	}
	// 更新第三方支付信息为支付完成
	if _, err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(dao.PmsTransaction.Columns().PaymentRequestId, in.TransNo).Update(updateData); err != nil {
		err = gerror.New("第三方支付信息更新失败")
		return
	}
	if PmsTransaction.Scene == "BOOKING" {
		if err = s.PayAmountChange(ctx, tx, PmsTransaction.OrderSn); err != nil {
			return
		}
	}

	if OrderStatus == "WAIT_PAY" || OrderStatus == "ING" {
		if PmsTransaction.OrderType != "BOOKING_CHANGE" {
			if err = service.PayService().OrderBalancePay(ctx, tx, OrderSn, MemberId, PayType); err != nil {
				return
			}
		}
	}

	return
}

func (s *sPayService) PayAmountChange(ctx context.Context, tx gdb.TX, OrderSn string) (err error) {
	var (
		PmsTransaction []*entity.PmsTransaction
		AllPayPrice    float64
	)
	if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(g.MapStrAny{
		dao.PmsTransaction.Columns().OrderSn:   OrderSn,
		dao.PmsTransaction.Columns().PayStatus: "DONE",
	}).Scan(&PmsTransaction); err != nil {
		return
	}
	if g.IsEmpty(PmsTransaction) {
		return
	}
	// 计算总计支付金额
	for _, Transaction := range PmsTransaction {
		AllPayPrice = decimal.NewFromFloat(AllPayPrice).Add(decimal.NewFromFloat(Transaction.PayAmount)).Round(0).InexactFloat64()
	}
	// 更新到主订单
	_, err = dao.PmsAppStay.Ctx(ctx).TX(tx).
		Where(dao.PmsAppStay.Columns().OrderSn, OrderSn).
		Update(g.Map{
			dao.PmsAppStay.Columns().OrderAmount: AllPayPrice,
		})
	return
}

func (s *sPayService) HandleFoodOrderMq(ctx context.Context, OrderSn string, Logger *glog.Logger) (err error) {
	// TODO 餐饮订单支付完成业务
	var (
		gHttpClient = g.Client()
		response    *gclient.Response
	)
	gHttpClient.SetHeader("Content-Type", "application/json")
	if response, err = gHttpClient.Post(ctx, "http://127.0.0.1:9000/food/pay/payNotify", g.MapStrAny{
		"orderSn": OrderSn,
	}); err != nil {
		return
	}
	Logger.Info(ctx, response.Raw())

	// 打印
	_ = service.BasicsPrinter().PrinterFoodOrder(ctx, &input_basics.PrinterCarOrderInp{
		OrderSn: OrderSn,
	})

	if gjson.New(response.ReadAll()).Get("code").Int() == 0 {
		return
	}
	return
}

func (s *sPayService) HandleSpaOrderMq(ctx context.Context, OrderSn string, Logger *glog.Logger) (err error) {
	// TODO SPA订单支付完成业务
	var (
		gHttpClient = g.Client()
		response    *gclient.Response
	)
	gHttpClient.SetHeader("Content-Type", "application/json")
	if response, err = gHttpClient.Post(ctx, "http://127.0.0.1:9000/spa/pay/payNotify", g.MapStrAny{
		"orderSn": OrderSn,
	}); err != nil {
		return
	}
	Logger.Info(ctx, response.Raw())

	// 打印
	_ = service.BasicsPrinter().PrinterSpaOrder(ctx, &input_basics.PrinterCarOrderInp{
		OrderSn: OrderSn,
	})

	if gjson.New(response.ReadAll()).Get("code").Int() == 0 {
		return
	}
	return
}

func (s *sPayService) HandleCarOrderMq(ctx context.Context, OrderSn string, Logger *glog.Logger) (err error) {
	// TODO CAR订单支付完成业务
	var (
		gHttpClient = g.Client()
		response    *gclient.Response
	)
	gHttpClient.SetHeader("Content-Type", "application/json")
	if response, err = gHttpClient.Post(ctx, "http://127.0.0.1:9000/car/pay/payNotify", g.MapStrAny{
		"orderSn": OrderSn,
	}); err != nil {
		return
	}
	Logger.Info(ctx, response.Raw())

	// 打印
	_ = service.BasicsPrinter().PrinterCarOrder(ctx, &input_basics.PrinterCarOrderInp{
		OrderSn: OrderSn,
	})

	if gjson.New(response.ReadAll()).Get("code").Int() == 0 {
		return
	}
	return
}

func (s *sPayService) OrderBalancePay(ctx context.Context, tx gdb.TX, OrderSn string, MemberId int, PayType string) (err error) {
	var (
		PmsBalTransaction    *entity.PmsTransaction
		PmsCouponTransaction *entity.PmsTransaction
	)
	// 查询是否存在未支付的余额支付
	g.Log().Info(ctx, "查询是否存在未支付的余额支付")
	if err = dao.PmsTransaction.Ctx(ctx).TX(tx).
		Where(dao.PmsTransaction.Columns().OrderSn, OrderSn).
		Where(dao.PmsTransaction.Columns().PayStatus, "WAIT").
		Where(dao.PmsTransaction.Columns().PayType, "BAL").
		Scan(&PmsBalTransaction); err != nil && !errors.Is(err, sql.ErrNoRows) {
		return
	}
	// 是否存在未支付的余额支付信息
	if !g.IsEmpty(PmsBalTransaction) {
		// 扣除余额
		if err = service.AppMember().MemberBalanceChange(ctx, &input_app_member.MemberBalanceInp{
			MemberId:      MemberId,
			Scene:         PmsBalTransaction.Scene,
			Type:          "CONSUME",
			ChangeBalance: PmsBalTransaction.Amount * -1,
			OrderSn:       PmsBalTransaction.OrderSn,
			Des:           fmt.Sprintf("支付%s费用", PayType),
		}, tx); err != nil {
			// 退三方支付金额
			return
		}

		// 修改支付订单状态
		if _, err = dao.PmsTransaction.Ctx(ctx).TX(tx).OmitEmptyData().
			Where(dao.PmsTransaction.Columns().TransactionSn, PmsBalTransaction.TransactionSn).
			Where(dao.PmsTransaction.Columns().PayStatus, "WAIT").
			Update(entity.PmsTransaction{
				PayAmount: PmsBalTransaction.Amount,
				PayStatus: "DONE",
				PayTime:   gtime.Now(),
			}); err != nil {
			return
		}
	}

	// 查询优惠券支付明细情况
	if err = dao.PmsTransaction.Ctx(ctx).TX(tx).Where(g.MapStrAny{
		dao.PmsTransaction.Columns().OrderSn:   OrderSn,
		dao.PmsTransaction.Columns().PayType:   "COUPON",
		dao.PmsTransaction.Columns().PayStatus: "WAIT",
	}).Scan(&PmsCouponTransaction); err != nil {
		return
	}
	if !g.IsEmpty(PmsCouponTransaction) {
		// 核销优惠券
		if _, err = dao.PmsCoupon.Ctx(ctx).TX(tx).Where(dao.PmsCoupon.Columns().Id, PmsCouponTransaction.CouponId).Update(g.MapStrAny{
			dao.PmsCoupon.Columns().State:   2,
			dao.PmsCoupon.Columns().UseTime: gtime.Now(),
		}); err != nil {
			return
		}
	}
	return
}
